package com.education.business.service.system;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.education.business.mapper.system.SystemEmailAttachmentMapper;
import com.education.business.mapper.system.SystemEmailLogMapper;
import com.education.common.enums.EmailStatusEnum;
import com.education.model.dto.EmailLogQuery;
import com.education.model.dto.EmailMessage;
import com.education.model.dto.EmailStatistics;
import com.education.model.dto.EmailStatsQuery;
import com.education.model.entity.SystemEmailAttachment;
import com.education.model.entity.SystemEmailLog;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.data.domain.Pageable;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.time.LocalDateTime;
import java.util.List;

@Service
@RequiredArgsConstructor
public class SysEmailServiceImpl extends ServiceImpl<SystemEmailLogMapper, SystemEmailLog>  {

    private final JavaMailSender mailSender;
    private final SystemEmailAttachmentMapper attachmentMapper;


    @Value("${spring.mail.username}")
    private String fromEmail;

    @Transactional
    public void sendAndLogEmail(EmailMessage emailMessage) {
        // 创建日志记录
        SystemEmailLog log = createLogRecord(emailMessage);

        try {
            // 发送邮件
            sendEmail(emailMessage);

            // 更新状态为成功
            log.setStatus(EmailStatusEnum.SUCCESS.getValue());
            log.setUpdateTime(LocalDateTime.now());
            this.updateById(log);
        } catch (Exception e) {
            // 更新状态为失败并记录错误信息
            log.setStatus(EmailStatusEnum.FAILED.getValue());
            log.setErrorMessage(e.getMessage());
            log.setUpdateTime(LocalDateTime.now());
            this.updateById(log);
            throw new EmailSendException("邮件发送失败", e);
        }
    }

    private void sendEmail(EmailMessage emailMessage) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        helper.setFrom(fromEmail);
        helper.setTo(emailMessage.getEmail());
        helper.setSubject(emailMessage.getSubject());
        helper.setText(emailMessage.getContent(), emailMessage.isHtml());

        // 添加附件
        if (emailMessage.getAttachments() != null) {
            for (EmailMessage.Attachment attachment : emailMessage.getAttachments()) {
                helper.addAttachment(
                        attachment.getFilename(),
                        new ByteArrayResource(attachment.getData())
                );
            }
        }

        mailSender.send(message);
    }

    private SystemEmailLog createLogRecord(EmailMessage emailMessage) {
        SystemEmailLog log = new SystemEmailLog();
        log.setSender(fromEmail);
        log.setRecipient(emailMessage.getEmail());
        log.setSubject(emailMessage.getSubject());
        log.setContent(emailMessage.getContent());
        log.setHtml(emailMessage.isHtml());
        log.setSendTime(LocalDateTime.now());
        log.setCreateTime(LocalDateTime.now());
        log.setStatus(EmailStatusEnum.PENDING.getValue());

        // 保存主记录
        this.save(log);

        // 保存附件
        if (emailMessage.getAttachments() != null) {
            for (EmailMessage.Attachment att : emailMessage.getAttachments()) {
                SystemEmailAttachment attachment = new SystemEmailAttachment();
                attachment.setEmailLogId(log.getId());
                attachment.setFilename(att.getFilename());
                attachment.setFileSize((long) att.getData().length);
                attachmentMapper.insert(attachment);
            }
        }

        return log;
    }

    public SystemEmailLog getEmailLogDetail(Long logId) {
        SystemEmailLog log = this.getById(logId);
        if (log != null) {
            List<SystemEmailAttachment> attachments = attachmentMapper.selectByEmailLogId(logId);
            log.setAttachments(attachments);
        }
        return log;
    }

    public Page<SystemEmailLog> getEmailLogs(EmailLogQuery query, Pageable pageable) {
        Page<SystemEmailLog> page = new Page<>(pageable.getPageNumber(), pageable.getPageSize());

        LambdaQueryWrapper<SystemEmailLog> wrapper = new LambdaQueryWrapper<>();
        if (query.getRecipient() != null) {
            wrapper.eq(SystemEmailLog::getRecipient, query.getRecipient());
        }
        if (query.getStatus() != null) {
            wrapper.eq(SystemEmailLog::getStatus, query.getStatus());
        }
        if (query.getStartTime() != null && query.getEndTime() != null) {
            wrapper.between(SystemEmailLog::getSendTime, query.getStartTime(), query.getEndTime());
        }

        return this.page(page, wrapper);
    }

    @Transactional
    public boolean retryFailedEmail(Long logId) {
        SystemEmailLog log = this.getById(logId);
        if (log == null || !EmailStatusEnum.FAILED.getValue().equals(log.getStatus())) {
            return false;
        }

        EmailMessage message = convertToEmailMessage(log);
        sendAndLogEmail(message);
        return true;
    }

    public EmailStatistics getEmailStatistics(EmailStatsQuery query) {
        LocalDateTime start = query.getStartTime() != null ? query.getStartTime() : LocalDateTime.now().minusDays(30);
        LocalDateTime end = query.getEndTime() != null ? query.getEndTime() : LocalDateTime.now();

        Integer total = this.baseMapper.countByTimeRange(start, end);
        Integer success = this.baseMapper.countByStatusAndTimeRange(EmailStatusEnum.SUCCESS.getValue(), start, end);
        Integer failed = this.baseMapper.countByStatusAndTimeRange(EmailStatusEnum.FAILED.getValue(), start, end);

        return new EmailStatistics(total, success, failed);
    }

    private EmailMessage convertToEmailMessage(SystemEmailLog log) {
        return EmailMessage.builder()
                .email(log.getRecipient())
                .subject(log.getSubject())
                .content(log.getContent())
                .isHtml(log.getHtml())
                .build();
    }

    public static class EmailSendException extends RuntimeException {
        public EmailSendException(String message, Throwable cause) {
            super(message, cause);
        }
    }

}
